#include "Algorytmy.h"
#include "Punkt.h"
#include <iostream>
#include <fstream>
#include <algorithm>
#include <sstream>

using namespace std;

namespace Algorytmy {

    const int maxI = 181;
    const int maxJ = 297;

    //==============================================================================
    // Obszar = 1;

    void wykryjPodloge(Skan3D* s) {
        std::cout << std::endl << "Algorytmy::wykryjPodloge():" << std::endl;
        double maxZ = -100;
        double minZ = 100;
        double maxX = -100;
        double minX = 100;
        double maxY = -100;
        double minY = 100;
        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {
                Punkt* p = &(s->punkt[w][k]);
                if (p->Obszar != 0) continue;
                if (p->z < -0.30) {
                    // cout << "(" << w << ";" << k << ") = " << p->z << endl;
                    // p->Obszar = OB_Podloga;
                    p->Obszar = 1;
                }

                if (p->z > maxZ) maxZ = p->z;
                if (p->z < minZ) minZ = p->z;

                if (p->y > maxY) maxY = p->y;
                if (p->y < minY) minY = p->y;

                if (p->x > maxX) maxX = p->x;
                if (p->x < minX) minX = p->x;

            }//k++
        }//w++

        std::cout << "maxZ: " << maxZ << " minZ: " << minZ << std::endl;
        std::cout << "dZ: " << maxZ - minZ << std::endl;

        std::cout << "maxY: " << maxY << " minY: " << minY << std::endl;
        std::cout << "dY: " << maxY - minY << std::endl;

        std::cout << "maxX: " << maxX << " minX: " << minX << std::endl;
        std::cout << "dx: " << maxX - minX << std::endl;
    }//void

    //==============================================================================

    void rysujElement(Skan3D* s, int obszar, char* nazwaPliku) {

        FILE* f = fopen(nazwaPliku, "w");
        fclose(f);
        std::fstream plik(nazwaPliku, std::ios::in | std::ios::out);
        if (plik.fail()) { //nie ma pliku
            std::cout << "Brak Pliku!" << std::endl;
        }
        plik << "P1" << std::endl;
        plik << s->maxK << " " << s->maxW << std::endl;

        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {
                if (s->punkt[w][k].Obszar == obszar)
                    plik << "1 ";
                else
                    plik << "0 ";
            }
            plik << std::endl;
        }
        plik.close();

    }//void
    //==============================================================================

    void rysuj(Skan3D* s, char* nazwaPliku) {

        FILE* f = fopen(nazwaPliku, "w");
        fclose(f);
        std::fstream plik(nazwaPliku, std::ios::in | std::ios::out);
        if (plik.fail()) { //nie ma pliku
            std::cout << "Brak Pliku!" << std::endl;
        }
        plik << "P2" << std::endl;
        int maxObszar = 0;
        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {
                if (maxObszar < s->punkt[w][k].Obszar) maxObszar = s->punkt[w][k].Obszar;
            }

        }
        plik << s->maxK << " " << s->maxW << std::endl;
        plik << maxObszar << endl;

        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {
                plik << ((s->punkt[w][k].Obszar < 0) ? 0 : s->punkt[w][k].Obszar) << " ";
                //plik << s->punkt[w][k].Obszar << " ";
            }
            plik << std::endl;
        }
        plik.close();

    }
    //==============================================================================
    // Obszar = 2;

    void wykryjSufit(Skan3D* s) {
        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {

                Punkt* p = &(s->punkt[w][k]);
                if (p->Obszar != 0) continue;
                if (p->z > 1.5) {
                    // cout << "(" << w << ";" << k << ") = " << p->z << endl;
                    //p->Obszar = OB_Sufit;
                    p->Obszar = 2;
                }
            }//k++
        }//w++
    }//void
    //==============================================================================

    void generujPlik_XYZEtykieta(Skan3D* s, char* nazwaPliku) {

        FILE* f = fopen(nazwaPliku, "w");
        fclose(f);
        std::fstream plik(nazwaPliku, std::ios::in | std::ios::out);
        if (plik.fail()) { //nie ma pliku
            std::cout << "Brak Pliku!" << std::endl;
        }
        plik << "# linia 1. Kolumy,\n#linia 2. Wiersze,\n# kolejno X Y Z Etykieta" << std::endl;
        plik << "#Etykiety: OB_zaDaleko = -2, OB_nieZdefiniowany = -1, OB_niePrzydzielony = 0, OB_Podloga = 1, OB_Sufit = 2" << std::endl;
        plik << s->maxK << std::endl << s->maxW << std::endl;

        for (int w = 0; w < s->maxW; w++) {
            for (int k = 0; k < s->maxK; k++) {
                Punkt p = s->punkt[w][k];
                plik << p.x << " " << p.y << " " << p.z << " " << p.Obszar << std::endl;
            }
            //plik << std::endl;
        }
        plik.close();

    }//void
    //==============================================================================

    void wykryjObszary(Skan3D* s) {

        double minDystans = 0.2;
        int NumerObszar = 3;
        s->punkt[0][0].Obszar = NumerObszar;

        //=== === pierwsza kolumna
        for (int k = 1; k < s->maxK; k++) {
            Punkt* p = &(s->punkt[0][k]);
            if (p->Obszar != 0) continue;
            if (p->odleglosc(s->punkt[0][k - 1]) < minDystans
                    && s->punkt[0][k - 1].Obszar != 1
                    && s->punkt[0][k - 1].Obszar != 2) {
                p->Obszar = s->punkt[0][k - 1].Obszar;
            } else {
                p->Obszar = ++NumerObszar;
            }
        }//for k++

        //=== === pierwszy wiersz
        for (int w = 1; w < s->maxW; w++) {
            Punkt* p = &(s->punkt[w][0]);
            if (p->Obszar != 0) continue;
            if (p->odleglosc(s->punkt[w - 1][0]) < minDystans
                    && s->punkt[w - 1][0].Obszar != 1
                    && s->punkt[w - 1][0].Obszar != 2) {
                p->Obszar = s->punkt[w - 1][0].Obszar;
            } else {
                p->Obszar = ++NumerObszar;
            }
        }//for w++

        //=== === cala reszta
        for (int w = 1; w < s->maxW; w++) {
            for (int k = 1; k < s->maxK; k++) {

                Punkt* p = &(s->punkt[w][k]);
                if (p->Obszar != 0) continue;

                Punkt* p10 = &(s->punkt[w - 1][k]);
                Punkt* p01 = &(s->punkt[w][k - 1]);
                Punkt* p11 = &(s->punkt[w - 1][k - 1]);

                double odl10 = p->odleglosc(p10);
                double odl01 = p->odleglosc(p01);
                double odl11 = p->odleglosc(p11);

                Punkt* pXX;
                double minOdl = 100;

                if (odl10 <= odl01 && odl10 <= odl11) {
                    pXX = p10;
                    minOdl = odl10;
                }
                if (odl01 <= odl10 && odl01 <= odl11) {
                    pXX = p01;
                    minOdl = odl01;
                }
                if (odl11 <= odl01 && odl11 <= odl10) {
                    pXX = p10;
                    minOdl = odl11;
                }

                if (minOdl < minDystans
                        && pXX->Obszar != 1
                        && pXX->Obszar != 2) {
                    p->Obszar = pXX->Obszar;
                } else {
                    p->Obszar = ++NumerObszar;
                }

            }//k++
        }//w++
    }//void
    //==============================================================================
    /*
        bool czyNalezyDoObszaru(vektor<Punkt*> ob, Punkt* p, double prog) {
            return false;
        }
     */
    //==============================================================================

    int nrMin(double* t, int rozmiar) {
        int nr = -1;
        double war = 1000000000;
        for (int i = 0; i < rozmiar; i++) {
            if (t[i] < war) {
                war = t[i];
                nr = i;
            }

        }
        return nr;
    }

/**
     *
     */
    std::vector< std::vector<int> > wczytaj(std::string scieszka) {

        ifstream plik(scieszka.c_str());
        std::vector< std::vector<int> > M;

        //konfiguruje wektor-kolumne tak, zeby miescil size wektorów-wiersze
        M.resize(maxJ);
        //konfiguruje wektory-wiersze tak, aby kazdy zmiescil size+1 liczb
        for (int j = 0; j < maxJ; j++) {
            M[j].resize(maxI);
        }


        std::string wiersz;
        while (getline(plik, wiersz)) {
            //pomijamy komentarze
            if (wiersz.find("#") != string::npos) continue;
            //
            std::stringstream ssWiersz(wiersz);
            int i, j, k;
            ssWiersz >> i >> j >> k;
            M[j][i] = k;
        }//while

        return M;
    }

    //==============================================================================

    void rysuj(std::vector< std::vector<int> > m, string scieszka) {

        FILE* f = fopen(scieszka.c_str(), "w");
        fclose(f);
        std::fstream plik(scieszka.c_str(), std::ios::in | std::ios::out);
        if (plik.fail()) { //nie ma pliku
            std::cout << "Brak Pliku!" << std::endl;
        }
        plik << "P2" << std::endl;
        int maxObszar = 0;
        for (int w = 0; w < m.size(); w++) {
            for (int k = 0; k < m[w].size(); k++) {
                if (maxObszar < m[w][k]) maxObszar = m[w][k];
            }

        }
        plik << maxI << " " << maxJ << std::endl;
        //plik << maxObszar << endl;
        plik << 10 << endl;

        for (int w = 0; w < m.size(); w++) {
            for (int k = 0; k < m[w].size(); k++) {
                plik << (m[w][k] > 9 ? 0 : m[w][k]) << " ";
                //plik << "x";
            }
            plik << std::endl;
        }
        plik.close();

    }
};

